<?php
namespace TennisTournament\Persistent;

use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Query\Expr;
use TennisTournament\Model\Group;
use TennisTournament\Model\Match;
use TennisTournament\Model\StageOfTournamentEnum;

class MatchDaoDoctrine extends GenericDaoDoctrine implements MatchDao {

    const MATCH_ENTITY = "TennisTournament\Model\Match";

    public function __construct(EntityManager $entityManager) {
        parent::__construct($entityManager, self::MATCH_ENTITY);
    }

    /**
     * Fetch all matches based on their state of tournament
     * @param $stageOfTournament string from {@link StageOfTournamentEnum}
     * @throws \LogicException if $stageOfTournament is not one from {@link StageOfTournamentEnum}
     * @return array from all matches or null if doesn't exist such matches
     */
    public function fetchAllWithStageOfTournament($stageOfTournament){
        /** @var $desiredStageOfGame string */
        $desiredStageOfGame = null;

        switch($stageOfTournament) {
            case StageOfTournamentEnum::GROUP_STAGE:
                $desiredStageOfGame = $stageOfTournament;
                break;
            case StageOfTournamentEnum::SECOND_STAGE:
                $desiredStageOfGame = $stageOfTournament;
                break;
            case StageOfTournamentEnum::QUARTERFINAL:
                $desiredStageOfGame = $stageOfTournament;
                break;
            case StageOfTournamentEnum::SEMIFINAL:
                $desiredStageOfGame = $stageOfTournament;
                break;
            case StageOfTournamentEnum::THIRD_PLACE:
                $desiredStageOfGame = $stageOfTournament;
                break;
            case StageOfTournamentEnum::FINAL_STAGE:
                $desiredStageOfGame = $stageOfTournament;
                break;
            default:
                throw new \LogicException("State with such id doesn't exist");
        }

        $queryBuilder = $this->entityManager->createQueryBuilder();

        $queryBuilder->select('match')
            ->from(self::MATCH_ENTITY, "match")
            ->where($queryBuilder->expr()->eq('match.stageOfTournament', ':stage'))
            ->orderBy('match.date', 'DESC')
            ->addOrderBy('match.id', 'ASC')
            ->setParameter("stage", $stageOfTournament);


        $result = $queryBuilder->getQuery()->getResult();

        return $result;
    }

    /**
     * Update Match entity
     * @param Match $match
     * @return void
     */
    public function update(Match $match) {
        $this->entityManager->merge($match);
        $this->entityManager->flush();
    }

    /**
     * Fetch all matches played in specific Groups
     * @param Group $group
     * @return array | null
     */
    public function getAllMatchesBy(Group $group) {
        $qb = $this->entityManager->createQueryBuilder();

        $qb->select('m')
            ->from(self::MATCH_ENTITY, 'm')
            ->innerJoin('m.playerHost', 'pl', Expr\Join::WITH,
                $qb->expr()->orX(
                    $qb->expr()->eq('m.playerHost', 'pl'),
                    $qb->expr()->eq('m.playerGuest', 'pl')
                )
            )->innerJoin('pl.groupStats', 'grst', Expr\Join::WITH,
                $qb->expr()->eq('pl', 'grst.player')
            )->innerJoin('grst.group', 'gr', Expr\Join::WITH,
                $qb->expr()->eq('grst.group', 'gr')
            )->where($qb->expr()->eq('gr.name', ':name'))
            ->setParameter('name', $group->getName());

        $result = $qb->getQuery()->getResult();

        for ($i = 0; $i < count($result); $i++) {
            $result[$i]->setResults($result[$i]->getResults()->toArray());
        }


    	return $result;
    }

    /**
     * Retrieve all Matches who are played in the current date
     * @param \DateTime $date
     * @return array
     */
    public function getAllMatchesByDate(\DateTime $date) {
        $qb = $this->entityManager->createQueryBuilder();

        $qb->select('m')
           ->from(self::MATCH_ENTITY, 'm')
           ->where($qb->expr()->eq('m.date', ':date'))
           ->setParameter('date', $date->format('Y-m-d'));

        $result = $qb->getQuery()->getResult();

        for ($i = 0; $i < count($result); $i++) {
            $result[$i]->setResults($result[$i]->getResults()->toArray());
        }

        return $result;
    }


    /**
     * Check whether all matches in specific stage of tournament are played yet or not.
     * @param $stageOfTournament string
     * @return boolean
     */
    public function isPlayedAllMatchesInStageOfTournament($stageOfTournament) {
        $qb = $this->entityManager->createQueryBuilder();

        $allMatches = (int) $qb->select($qb->expr()->count('M.id') . ' all_matches')
            ->from(self::MATCH_ENTITY, 'M')
            ->where($qb->expr()->eq('M.stageOfTournament', ':stage'))
            ->setParameter('stage', $stageOfTournament)->getQuery()->getSingleScalarResult();

        $playedMatches = (int)$qb->select($qb->expr()->count('M.id') . ' played_matches')
            ->where($qb->expr()->isNotNull('M.winner'))
            ->andwhere($qb->expr()->eq('M.stageOfTournament', ':stage'))
            ->setParameter('stage', $stageOfTournament)->getQuery()->getSingleScalarResult();

        return $allMatches == 0 ? false : $allMatches - $playedMatches == 0;
    }


}